package org.visionlibrary.image.filters.bluring;

import java.awt.Point;
import java.util.Collections;
import java.util.Vector;

import javax.media.jai.TiledImage;

import org.visionlibrary.image.model.WindowFilter;

//TODO: Przepisac na nowo aktualna wersja nie dziala
public class AdaptiveMedian extends WindowFilter {
	protected int width;

	protected int height;

	protected int maxWidth = 9;

	protected int maxHeight = 9;

	public AdaptiveMedian(int width, int height) {
		this.width = width;
		this.height = height;
	}

	public AdaptiveMedian(int size) {
		this(size, size);
	}

	public AdaptiveMedian() {
		this(3);
	}

	protected int getNewPixelVal(TiledImage src, Point p, int channel) {
		Vector<Integer> medianv = new Vector<Integer>();
		Point pIter = new Point();
		for (pIter.y = 0; pIter.y < windowHeight; pIter.y++)
			for (pIter.x = 0; pIter.x < windowWidth; pIter.x++) {
				int val = getWindowPixelVal(src, pIter, channel);
				medianv.add(new Integer(val));
			}

		Collections.sort(medianv);

		int med = medianv.elementAt(medianv.size() / 2).intValue();

		int max = getWindowPixelVal(src, new Point(0, 0), channel);
		for (pIter.y = 0; pIter.y < windowHeight; pIter.y++)
			for (pIter.x = 0; pIter.x < windowWidth; pIter.x++) {
				int val = getWindowPixelVal(src, pIter, channel);
				if (val > max)
					max = val;
			}

		int min = getWindowPixelVal(src, new Point(0, 0), channel);
		for (pIter.y = 0; pIter.y < windowHeight; pIter.y++)
			for (pIter.x = 0; pIter.x < windowWidth; pIter.x++) {
				int val = getWindowPixelVal(src, pIter, channel);
				if (val < min)
					min = val;
			}
		int curr = getWindowPixelVal(src, dstPointInWindow, channel);

		return levelA(min, max, med, curr, src, p, channel);
	}

	private int levelA(int zmin, int zmax, int zmed, int zxy, TiledImage src,
			Point p, int channel) {
		int a1 = zmed - zmin;
		int a2 = zmed - zmax;
		if (a1 > 0 && a2 < 0) {
			return levelB(zmin, zmax, zmed, zxy);
		} else {
			windowWidth++;
			windowHeight++;
			dstPointInWindow = new Point(windowWidth / 2, windowHeight / 2);
			if (windowWidth > maxWidth || windowHeight > maxHeight)
				return zxy;
			else
				return zmed;
		}
	}

	private int levelB(int zmin, int zmax, int zmed, int zxy) {
		int b1 = zxy - zmin;
		int b2 = zxy - zmax;
		if (b1 > 0 && b2 < 0)
			return zxy;
		return zmed;
	}

	protected void setWindowProperties() {
		windowWidth = width;
		windowHeight = height;
		dstPointInWindow = new Point(width / 2, height / 2);
	}
}
